package com.jin.core.interceptors;

import com.auth0.jwt.interfaces.Claim;
import com.jin.Exception.http.ForbiddenException;
import com.jin.Exception.http.UnAuthenticatedException;
import com.jin.core.LocalUser;
import com.jin.model.User;
import com.jin.repository.UserRepository;
import com.jin.service.UserService;
import com.jin.util.JwtToken;
import jdk.nashorn.internal.parser.Token;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
import java.util.Optional;

//拦截不合规的token 拦截请求
//对于权限的实现
//这个类写完了还得进行注册
@Component
public class PermissionInterceptor extends HandlerInterceptorAdapter {
    @Autowired
    UserService userService;
    //请求进入controller之前的时候
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //获取注解
        ScopeLevel scopeLevel = getScopeLevel(handler);
        //如果方法上没有注解，是个公开的方法
        if (scopeLevel==null){
             return true;
        }
        //按照规定token是放在header里面所以后面传入Authorization
        String bearerToken = request.getHeader("Authorization");
        //如果访问受控的api连token都没有
        if (StringUtils.isEmpty(bearerToken)){
            throw new UnAuthenticatedException(10004);
        }
        //判断token是不是以Bearer结尾的
        if (!bearerToken.startsWith("Bearer")){
            throw new UnAuthenticatedException(10004);
        }
        //如果程序能走到这，就说明以上的情况都不属于，不是空值的token,并且是以bearer开头的，我们就获取他
        String tokens[] = bearerToken.split(" ");
        if (!(tokens.length == 2)){
            throw new UnAuthenticatedException(10004);
        }
        String token = tokens[1];
        //解析这个token
        Optional<Map<String, Claim>> optionalMap = JwtToken.getClaims(token);
        Map<String,Claim> map = optionalMap.orElseThrow(() -> new UnAuthenticatedException(10004));
        boolean valid = hasPermission(scopeLevel,map);
        if (valid){
            setToThreadLocal(map);
        }
        return valid;
    }

    //获取到用户的uid，传入到userService里面，查询出当前的用户对象，在放入localUser类里面去
    //用户的信息放在token令牌的claim中
    private void setToThreadLocal(Map<String, Claim> map){
        Long uid = map.get("uid").asLong();
        Integer scope = map.get("scope").asInt();
        //根据uid查询用户的对象
        User user = userService.getUserById(uid);
        LocalUser.set(user,scope);
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        super.postHandle(request, response, handler, modelAndView);
    }

    //清理资源
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //释放线程的资源,在请求结束的时候，释放ThreadLocal的线程资源
        LocalUser.clear();
        super.afterCompletion(request, response, handler, ex);
    }

    //读取注解里面的scopeLevel 返回一个注解 Object handler是方法，自然也就可以拿到对应的注解
    private ScopeLevel getScopeLevel(Object handler){
        if (handler instanceof HandlerMethod){
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            ScopeLevel scopeLevel = handlerMethod.getMethod().getAnnotation(ScopeLevel.class);
            if (scopeLevel==null){
                return null;
            }
            return scopeLevel;
        }
            return null;
    }

    //与API中的scope进行比较返回结果
    private boolean hasPermission(ScopeLevel scopeLevel,Map<String,Claim> map){
        //获取注解里面的level
        Integer level = scopeLevel.value();
        Integer scope = map.get("scope").asInt();
        if (level > scope){
            throw new ForbiddenException(10005);
        }
        return true;
    }
}
